package com.bootdo.app.common.utils;

import com.bootdo.app.common.constants.JWTConstants;
import com.bootdo.app.common.jwt.IJWTInfo;
import com.bootdo.app.common.jwt.JWTInfo;
import io.jsonwebtoken.*;
import java.util.Date;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.joda.time.DateTime;

/**
  * @auther: Along
  * @description: JWT工具类
  * @Date: created in 2020/4/5 0:23
  */
public class JWTUtil {

    private static RSAKeyCreator rsaKeyCreator = new RSAKeyCreator();
    private static String profiles = "version1";
// ---------------------生成token---------------------
    /**
     * 私钥文件加密token
     * @param jwtInfo
     * @param priKeyPath
     * @param expire
     * @return
     * @throws Exception
     */
    public static String generateToken(IJWTInfo jwtInfo, String priKeyPath, int expire) throws Exception {
        String compactJws = Jwts.builder()
                .setSubject(jwtInfo.getUserSessionKey())
                .claim(JWTConstants.JWT_KEY_USER_ID, jwtInfo.getUserId())
                .claim(JWTConstants.JWT_KEY_OPEN_ID, jwtInfo.getOpenId())
                .claim(JWTConstants.JWT_KEY_SID,jwtInfo.getUserSID())
                .setExpiration(DateTime.now().plusSeconds(expire).toDate())
                .signWith(SignatureAlgorithm.RS256, rsaKeyCreator.getPriKeyFromFile(priKeyPath))
                .compact();
        return compactJws;
    }

    /**
     * 私钥字节数据加密token
     * @param jwtInfo
     * @param priKey
     * @param expire
     * @return
     * @throws Exception
     */
    public static String generateToken(IJWTInfo jwtInfo, byte[] priKey, int expire) throws Exception {
        String compactJws = Jwts.builder()
                .setSubject(jwtInfo.getUserSessionKey())
                .claim(JWTConstants.JWT_KEY_USER_ID, jwtInfo.getUserId())
                .claim(JWTConstants.JWT_KEY_OPEN_ID, jwtInfo.getOpenId())
                .claim(JWTConstants.JWT_KEY_SID,jwtInfo.getUserSID())
                .setExpiration(DateTime.now().plusSeconds(expire).toDate())
                .signWith(SignatureAlgorithm.RS256, rsaKeyCreator.getPriKeyFromByte(priKey))
                .compact();
        return compactJws;
    }

// ---------------------解析token---------------------
    /**
     * 公钥文件解析token
     *
     * @param token
     * @return
     * @throws Exception
     */
    private static Jws<Claims> parserToken(String token, String pubKeyPath) throws Exception {
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(rsaKeyCreator.getPubKeyFromFile(pubKeyPath)).parseClaimsJws(token);
        return claimsJws;
    }
    /**
     * 公钥字节数据解析token
     *
     * @param token
     * @return
     * @throws Exception
     */
    private static Jws<Claims> parserToken(String token, byte[] pubKey) throws Exception {
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(rsaKeyCreator.getPubKeyFromByte(pubKey)).parseClaimsJws(token);
        return claimsJws;
    }

// ---------------------获取token信息---------------------
    /**
     * 通过公钥文件获取token中的用户信息
     *
     * @param token
     * @param pubKeyPath
     * @return
     * @throws Exception
     */
    public static IJWTInfo getInfoFromToken(String token, String pubKeyPath) throws Exception {
        Jws<Claims> claimsJws = parserToken(token, pubKeyPath);
        Claims body = claimsJws.getBody();
        String sessionKey = body.getSubject();
        String userId = String.valueOf(body.get(JWTConstants.JWT_KEY_USER_ID));
        String openId = String.valueOf(body.get(JWTConstants.JWT_KEY_OPEN_ID));
        String sid = String.valueOf(body.get(JWTConstants.JWT_KEY_SID));
        return new JWTInfo(openId,userId,sessionKey,sid);
    }
    /**
     * 通过字节数据获取token中的用户信息
     *
     * @param token
     * @param pubKey
     * @return
     * @throws Exception
     */
    public static IJWTInfo getInfoFromToken(String token, byte[] pubKey) throws Exception {
        Jws<Claims> claimsJws = parserToken(token, pubKey);
        Claims body = claimsJws.getBody();
        String sessionKey = body.getSubject();
        String userId = String.valueOf(body.get(JWTConstants.JWT_KEY_USER_ID));
        String openId = String.valueOf(body.get(JWTConstants.JWT_KEY_OPEN_ID));
        String sid = String.valueOf(body.get(JWTConstants.JWT_KEY_SID));
        return new JWTInfo(openId,userId,sessionKey,sid);
    }
    
    
    /**
     * 创建jwt
     *
     * @param id
     * @param ttlMillis
     * @return
     * @throws Exception
     */
    public String createJWT(String id, long ttlMillis) throws Exception {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey key = generalKey();
        JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
                .setId(id)
                .setIssuedAt(now)
                .signWith(signatureAlgorithm, key);
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }
    
    /**
     * 由字符串生成加密key
     *
     * @return
     */
    public static SecretKey generalKey() {
        String stringKey = profiles + Constant.JWT_SECRET;
        byte[] encodedKey = Base64.decodeBase64(stringKey);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
}
